package com.yanqu.road.server.gameplayer.module.activity.springdraw;

import com.alibaba.fastjson.JSONObject;
import com.yanqu.road.dao.impl.activity.springdraw.SpringDrawUserDataDaoImpl;
import com.yanqu.road.entity.activity.ActivityInfo;
import com.yanqu.road.entity.activity.springdraw.SpringDrawOnceDrawResult;
import com.yanqu.road.entity.activity.springdraw.data.SpringDrawUserData;
import com.yanqu.road.entity.activity.springdraw.config.SpringDrawConfig;
import com.yanqu.road.entity.activity.springdraw.config.SpringDrawDigRewardConfig;
import com.yanqu.road.entity.activity.springdraw.enums.SpringDrawPassTypeEnum;
import com.yanqu.road.entity.config.goods.GoodsInfo;
import com.yanqu.road.entity.enums.*;
import com.yanqu.road.entity.log.springdraw.LogActivitySpringDrawDraw;
import com.yanqu.road.entity.player.UserActivityScore;
import com.yanqu.road.exception.BusinessException;
import com.yanqu.road.logic.helper.ActivityHelper;
import com.yanqu.road.pb.activity.SpringDrawProto;
import com.yanqu.road.server.GameServer;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.activity.ActivityMallModule;
import com.yanqu.road.server.gameplayer.module.base.GeneralModule;
import com.yanqu.road.server.gameplayer.module.player.CurrencyModule;
import com.yanqu.road.server.manger.ServerListMgr;
import com.yanqu.road.server.manger.activity.NormalActivityMgr;
import com.yanqu.road.server.manger.activity.springdraw.SpringDrawMgr;
import com.yanqu.road.server.manger.activity.springdraw.pb.SpringDrawPb;
import com.yanqu.road.server.manger.config.SystemOpenMgr;
import com.yanqu.road.server.manger.log.AutoLogMgr;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.server.protocol.Protocol;
import com.yanqu.road.utils.nline.NLineHelper;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;
import com.yanqu.road.utils.string.StringUtils;

import java.math.BigInteger;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

public class SpringDrawModule extends GeneralModule {

    //玩家活动数据MAP。K:活动ID,V:玩家活动数据
    private Map<Integer, SpringDrawUserData> userDataMap = new ConcurrentHashMap<>();

    public SpringDrawModule(GamePlayer player) {
        super(player);
    }

    @Override
    public boolean loadData() {
        SpringDrawUserDataDaoImpl userDataDao = new SpringDrawUserDataDaoImpl();
        List<ActivityInfo> activityList = NormalActivityMgr.getOpenActivityInfoList(eActivityType.SpringDraw.getValue());
        for (ActivityInfo activityInfo : activityList) {
            SpringDrawUserData userData = userDataDao.getUserData(activityInfo.getActivityId(), this.getUserId());
            if (userData != null) {
                this.userDataMap.put(userData.getActivityId(), userData);
            }
        }
        return true;
    }

    @Override
    public boolean afterLoadData() {
        return true;
    }

    @Override
    public boolean saveData() {
        //存储玩家数据
        SpringDrawUserDataDaoImpl userDataDao = new SpringDrawUserDataDaoImpl();
        for (SpringDrawUserData userData : this.userDataMap.values()) {
            if (userData.isInsertOption()) {
                userDataDao.add(userData);
            } else if (userData.isUpdateOption()) {
                userDataDao.update(userData);
            }
        }
        return true;
    }

    @Override
    public void afterLogin() {
        //同步活动配置
        this.syncConfig();
        //同步玩家活动数据
        this.syncUserDataMsg();
    }

    /**
     * 同步活动专属配置
     */
    public void syncConfig() {
        //系统解锁了才同步
        if (!SystemOpenMgr.systemOpen(player, eSystemId.SpringDraw.getValue())) {
            return;
        }
        //同步
        List<ActivityInfo> activityList = NormalActivityMgr.getOpenActivityInfoList(eActivityType.SpringDraw.getValue());
        for (ActivityInfo activityInfo : activityList) {
            SpringDrawConfig springDrawConfig = SpringDrawMgr.getActivityConfig(activityInfo.getActivityId());
            if (springDrawConfig != null) {
                SpringDrawProto.SpringDrawConfigSyncMsg.Builder syncMsg = SpringDrawProto.SpringDrawConfigSyncMsg.newBuilder();
                syncMsg.setActivityId(springDrawConfig.getActivityInfo().getActivityId());
                for (SpringDrawDigRewardConfig springDrawDigRewardConfig : springDrawConfig.getDigRewardConfigMap().values()) {
                    SpringDrawProto.SpringDrawDigRewardConfig.Builder digPb = SpringDrawPb.buildSpringDrawDigRewardConfig(springDrawDigRewardConfig);
                    syncMsg.addSpringDrawDigRewardConfig(digPb);
                }
                player.sendPacket(Protocol.U_SPRING_DRAW_CONFIG_SYNC, syncMsg);
            }
        }
    }

    /**
     * 同步玩家数据
     */
    public void syncUserDataMsg() {
        //系统解锁了才同步
        if (!SystemOpenMgr.systemOpen(player, eSystemId.SpringDraw.getValue())) {
            return;
        }
        //获取活动
        List<ActivityInfo> activityList = NormalActivityMgr.getOpenActivityInfoList(eActivityType.SpringDraw.getValue());
        //同步玩家数据
        for (ActivityInfo activityInfo : activityList) {
            SpringDrawProto.SpringDrawUserDataSyncMsg.Builder syncMsg = SpringDrawProto.SpringDrawUserDataSyncMsg.newBuilder();
            SpringDrawProto.SpringDrawUserDataTemp.Builder userDataBuild = SpringDrawPb.buildSpringDrawUserDataTemp(activityInfo.getActivityId(), player.getUserId(), userDataMap.get(activityInfo.getActivityId()));
            syncMsg.setUserData(userDataBuild);
            player.sendPacket(Protocol.U_SPRING_DRAW_USER_DATA_SYNC, syncMsg);
        }
    }

    /**
     * 获取玩家数据
     * @param activityId
     * @return
     */
    public SpringDrawUserData getUserData(int activityId) {
        return this.userDataMap.get(activityId);
    }

    /**
     * 获取玩家数据，不存在创建
     * @param activityId
     * @return
     */
    public synchronized SpringDrawUserData getUserDataAndCreate(int activityId, SpringDrawConfig config) {
        SpringDrawUserData userData = this.getUserData(activityId);
        if (userData == null) {
            //创建玩家数据
            userData = new SpringDrawUserData(
                    activityId,
                    player.getUserId(),
                    config.getNewBoard());
            this.userDataMap.put(activityId, userData);
        }
        return userData;
    }

//    /**
//     * 初始化玩家活动数据
//     */
//    public void initUserData() {
//        //系统解锁了才初始化
//        if (!SystemOpenMgr.systemOpen(player, eSystemId.SpringDraw.getValue())) {
//            return;
//        }
//        //获取活动
//        List<ActivityInfo> activityList = NormalActivityMgr.getOpenActivityInfoList(eActivityType.SpringDraw.getValue());
//        for (ActivityInfo activityInfo : activityList) {
//            if (this.userDataMap.get(activityInfo.getActivityId()) == null) {
//                //创建玩家数据
//                SpringDrawUserData userData = new SpringDrawUserData(
//                        activityInfo.getActivityId(),
//                        player.getUserId(),
//                        this.getNewBoard());
//                this.userDataMap.put(activityInfo.getActivityId(), userData);
//            }
//        }
//    }

    /**
     * 通用校验
     * @throws BusinessException
     */
    private void checkCommon(int activityId) throws BusinessException {
        //判断活动
        ActivityInfo activityInfo = NormalActivityMgr.getActivityInfo(activityId);
        if (activityInfo == null) {
            throw BusinessException.newException(GameErrorCode.E_ACTIVITY_NO_FOUND);
        }
        //判断是否在活动进行期
        if (!ActivityHelper.activityInShowTime(activityInfo)) {
            throw BusinessException.newException(GameErrorCode.E_COMMON_ACTIVITY_NO_IN_TIME);
        }
        //判断配置是否存在
        if (SpringDrawMgr.getActivityConfig(activityId) == null) {
            throw BusinessException.newException(GameErrorCode.E_SPRING_DRAW_CONFIG_NOT_FOUND);
        }
        //系统是否解锁
        if (!SystemOpenMgr.checkSystemOpen(this.getUserId(), eSystemId.SpringDraw.getValue())) {
            throw BusinessException.newException(GameErrorCode.E_SYSTEM_NO_OPEN);
        }
    }

    /**
     * 检查N * N 宫格，是个有连线。并返回连线编号。
     * @param board 棋盘
     * @return 连线编号数组
     * 垂直线（从左到右）：1, 2, 3...
     * 水平线（从上到下）：接着水平线编号，例如 4, 5, 6...
     * 对角线：紧接着垂直线编号，例如 7
     * 反对角线：去除反对角线连线编号
     * @param board
     * @return List<Integer> 连线编号数组
     */
    private List<Integer> checkLines(int[][] board) {
        List<Integer> lines = NLineHelper.checkLines(board);
        //业务特殊需求，去除反对角线
        int removeLineCode = board.length * 2 + 2;//反对角线的连续编号就是最后一个编号
        for (int i = 0; i < lines.size(); i++) {
            Integer lineCode = lines.get(i);
            if (lineCode == removeLineCode) {
                lines.remove(i);
                break;
            }
        }
        return lines;
    }

    /**
     * 进入下一关
     * @param userData
     */
    private synchronized void nextLevel(SpringDrawUserData userData) {
        //获取活动配置
        SpringDrawConfig config = SpringDrawMgr.getActivityConfig(userData.getActivityId());
        //下一关
        userData.setLevel(userData.getLevel() + 1);
        userData.setPassFlag(SpringDrawPassTypeEnum.SPRING_DRAW_PASS_NOT.getType());
        userData.setBoard(config.getNewBoard());
        userData.setBoardCreateTime(System.currentTimeMillis());
    }

    /**
     * 获取总积分
     * @param activityId
     * @return
     */
    public long getScore(int activityId) {
        //获取活动配置
        SpringDrawConfig config = SpringDrawMgr.getActivityConfig(activityId);
        //获取玩家积分
        UserActivityScore userActivityScore = player.getModule(ActivityMallModule.class).getUserActivityScore(activityId, config.getEXCHANGE_SCORE_ITEM_ID());
        if (userActivityScore != null) {
            return userActivityScore.getTotalScore();
        }
        return 0;
    }

    /*****************************************CMD**************************************************/

    /**
     * 进入活动
     * @param reqMsg
     * @return
     * @throws BusinessException
     */
    public synchronized SpringDrawProto.SpringDrawEnterActivityRespMsg.Builder enterActivity(SpringDrawProto.SpringDrawEnterActivityReqMsg reqMsg) throws BusinessException {
        SpringDrawProto.SpringDrawEnterActivityRespMsg.Builder respMsg = SpringDrawProto.SpringDrawEnterActivityRespMsg.newBuilder();
        //通用检测
        this.checkCommon(reqMsg.getActivityId());
        //获取活动配置
        SpringDrawConfig config = SpringDrawMgr.getActivityConfig(reqMsg.getActivityId());
        //进入活动，判断玩家数据是否存在
        SpringDrawUserData userData = this.getUserDataAndCreate(reqMsg.getActivityId(), config);
        //返回PB
        respMsg.setRet(0);
        respMsg.setUserData(SpringDrawPb.buildSpringDrawUserDataTemp(userData.getActivityId(), userData.getUserId(), userData));
        return respMsg;
    }

    /**
     * 浇灌
     * @param reqMsg
     * @return
     * @throws BusinessException
     */
    public synchronized SpringDrawProto.SpringDrawDrawingRespMsg.Builder drawing(SpringDrawProto.SpringDrawDrawingReqMsg reqMsg) throws BusinessException {
        SpringDrawProto.SpringDrawDrawingRespMsg.Builder respMsg = SpringDrawProto.SpringDrawDrawingRespMsg.newBuilder();
        //通用检测
        this.checkCommon(reqMsg.getActivityId());
        //获取活动配置
        SpringDrawConfig config = SpringDrawMgr.getActivityConfig(reqMsg.getActivityId());
        //获取玩家数据
        SpringDrawUserData userData = this.getUserDataAndCreate(reqMsg.getActivityId(), config);
        //判断是否过关，过关了就不能再浇灌
        if (userData.getPassFlag() == SpringDrawPassTypeEnum.SPRING_DRAW_PASS_YES.getType()) {
            throw BusinessException.newException(GameErrorCode.E_SPRING_DRAW_PASSED_NOT_DRAW);
        }
        //获取未浇灌的数量
        int notDrawNum = NLineHelper.checkNotCompleteNum(userData.getBoard());
        if (notDrawNum <= 0) {
            throw BusinessException.newException(GameErrorCode.E_SPRING_DRAW_DRAWING_FULL);
        }
        //获取关卡配置
        SpringDrawDigRewardConfig levelConfig = config.getDigRewardConfig(userData.getLevel());
        if (levelConfig == null) {
            throw BusinessException.newException(GameErrorCode.E_SPRING_DRAW_LEVEL_CONFIG_NOT_FOUND);
        }
        //判断浇灌一次的道具是否足够
        Property cost = new Property(config.getSPRING_DRAW_ITEM_ID(), levelConfig.getCost());
        if (!player.getModule(CurrencyModule.class).currencyIsEnough(cost)) {
            throw BusinessException.newException(GameErrorCode.E_SPRING_DRAW_DRAWING_PROP_NOT_ENOUGH);
        }
        //抽取次数
        int drawNum = reqMsg.getMulFlag() ? 10 : 1;
        drawNum = Math.min(notDrawNum, drawNum);
        //判断10连抽是否解锁
        if (reqMsg.getMulFlag() && userData.getDrawNum() < config.getSPRING_DRAW_TEN_GACHA_UNLOCK()) {
            throw BusinessException.newException(GameErrorCode.E_SPRING_DRAW_MUL_DRAW_LOCK);
        }

        //抽取
        AtomicLong allScore = new AtomicLong(0);
        Property allLineReward = new Property();
        List<int[]> positions = new ArrayList<>();
        //判断是指定抽取，还是随机抽取。渠道666才允许进行指定坐标浇灌（指定抽取是为了方便测试使用）
        if (!StringUtils.isNullOrEmpty(reqMsg.getAppointPositions()) && ServerListMgr.getChannelId(GameServer.getInstance().getServerId()) == 666) {
            //指定抽取
            String[] positionsStrArr = reqMsg.getAppointPositions().split(";");
            for (String positionsStr : positionsStrArr) {
                //解析一下指定的坐标
                String[] positionStrArr = positionsStr.split(",");
                int[] positionsArr = new int[2];
                for (int j = 0; j < positionsArr.length; j++) {
                    positionsArr[j] = Integer.parseInt(positionStrArr[j]);
                }
                //抽取一次
                boolean breakFlag = this.drawOneAndDataHandle(reqMsg.getActivityId(), allScore, allLineReward, positions, respMsg, positionsArr);
                if (breakFlag) {
                    break;
                }
             }
        } else {
            //随机抽取
            for (int i = 0; i < drawNum; i++) {
                //抽取一次
                boolean breakFlag = this.drawOneAndDataHandle(reqMsg.getActivityId(), allScore, allLineReward, positions, respMsg, null);
                if (breakFlag) {
                    break;
                }
            }
        }

        //当前玩家数据PB先构建一下
        SpringDrawProto.SpringDrawUserDataTemp.Builder userDataBuild = SpringDrawPb.buildSpringDrawUserDataTemp(userData.getActivityId(), userData.getUserId(), userData);
        respMsg.setUserData(userDataBuild);

        //日志
        LogActivitySpringDrawDraw logActivitySpringDrawDraw = new LogActivitySpringDrawDraw();
        logActivitySpringDrawDraw.setActivityId(reqMsg.getActivityId());
        logActivitySpringDrawDraw.setUserId(userData.getUserId());
        logActivitySpringDrawDraw.setLevel(userData.getLevel());
        logActivitySpringDrawDraw.setType(reqMsg.getMulFlag() ? 10 : 1);
        logActivitySpringDrawDraw.setGetScore(allScore.get());
        logActivitySpringDrawDraw.setNowScore(this.getScore(reqMsg.getActivityId()));
        logActivitySpringDrawDraw.setPosition(JSONObject.toJSONString(positions));
        logActivitySpringDrawDraw.setLineReward(PropertyHelper.parsePropertyToString(allLineReward));
        logActivitySpringDrawDraw.setPassReward(respMsg.getPassReward());
        AutoLogMgr.add(logActivitySpringDrawDraw);

        //判断棋盘是否满了，满了自动跳转到下一关
        if (NLineHelper.checkAllComplete(userData.getBoard())) {
            this.nextLevel(userData);
            SpringDrawProto.SpringDrawUserDataTemp.Builder nextLevelUserDataBuild = SpringDrawPb.buildSpringDrawUserDataTemp(userData.getActivityId(), userData.getUserId(), userData);
            respMsg.setNextLevelUserData(nextLevelUserDataBuild);
        }

        //构造PB
        respMsg.setRet(0);
        return respMsg;
    }

    /**
     * 抽取一次，并处理返回数据
     * @param activityId
     * @param appointPosition
     * @param allScore
     * @param allLineReward
     * @param positions
     * @param respMsg
     * @return 是否停止抽取。true：停止，false：不停止
     */
    private boolean drawOneAndDataHandle(int activityId, AtomicLong allScore, Property allLineReward, List<int[]> positions, SpringDrawProto.SpringDrawDrawingRespMsg.Builder respMsg, int[] appointPosition) {
        SpringDrawConfig config = SpringDrawMgr.getActivityConfig(activityId);
        //抽取一次
        SpringDrawOnceDrawResult onceDrawResult = this.drawOnce(activityId, appointPosition);
        if (onceDrawResult.isRet()) {
            allScore.addAndGet(onceDrawResult.getScoreReward().getGoods().getOrDefault(config.getEXCHANGE_SCORE_ITEM_ID(), BigInteger.ZERO).longValue());
            allLineReward.addProperty(onceDrawResult.getLineReward());
            positions.add(onceDrawResult.getPosition());

            respMsg.addScoreReward(PropertyHelper.parsePropertyToString(onceDrawResult.getScoreReward()));
            respMsg.addLineReward(PropertyHelper.parsePropertyToString(onceDrawResult.getLineReward()));
            if (onceDrawResult.getPassReward() != null && !onceDrawResult.getPassReward().isNothing()) {
                respMsg.setPassReward(PropertyHelper.parsePropertyToString(onceDrawResult.getPassReward()));
            }
            SpringDrawProto.SpringDrawBoardPositionTemp.Builder positionPb = SpringDrawPb.buildSpringDrawBoardPositionTemp(onceDrawResult.getPosition()[0], onceDrawResult.getPosition()[1]);
            respMsg.addPosition(positionPb);
            //判断这一次是否是触发过关的一抽，如果是，不在自动进行抽取
            if (onceDrawResult.isTriggerPassFlag()) {
                return true;
            }
        } else {
            return true;
        }
        return false;
    }

    public static void main(String[] args) {
        StringBuilder result = new StringBuilder();
        for (int i = 1; i <= 25; i++) {
            //人数
            int num = 50000;
            int lineNum = 0;
            int passNum = 0;
            for (int j = 0; j < num; j ++) {
                //棋盘
                int[][] board = new int[5][5];
                //每个人都进行抽取 i 次
                boolean lineFlag = false;
                boolean passFlag = false;
                for (int x = 0; x < i; x++) {
                    //棋盘随机落棋
                    NLineHelper.changeRandomZerosToOne(board);
                    //获取棋盘连线
                    List<Integer> lines = NLineHelper.checkLines(board);
                    //业务特殊需求，去除反对角线
                    int removeLineCode = board.length * 2 + 2;//反对角线的连续编号就是最后一个编号
                    for (int z = 0; z < lines.size(); z++) {
                        Integer lineCode = lines.get(z);
                        if (lineCode == removeLineCode) {
                            lines.remove(z);
                            break;
                        }
                    }

                    if (!lines.isEmpty()) {
                        lineFlag = true;
                    }
                    if (lines.size() >= 2) {
                        passFlag = true;
                    }
                }
                if (lineFlag) {
                    lineNum ++;
                }
                if (passFlag) {
                    passNum ++;
                }
            }
            result.append(i).append("抽，").append(lineNum).append("人连线，").append(passNum).append("人通过").append("\r\n");
        }
        System.out.println(result.toString());
    }

//    public static void main(String[] args) {
//        //k：关卡数，v：玩家数
//        Map<Integer, Integer> map = new HashMap<>();
//        int userNum = 50000;
//        for (int i = 0; i < userNum; i ++) {
//            int level = 1;
//            //抽取N次
//            int drawNum = 195;
//            int[][] board = new int[5][5];
//            for (int j = 0; j < drawNum; j++) {
//                //落盘
//                NLineHelper.changeRandomZerosToOne(board);
//                //棋盘连线数量
//                List<Integer> lines = NLineHelper.checkLines(board);
//                //业务特殊需求，去除反对角线
//                int removeLineCode = board.length * 2 + 2;//反对角线的连续编号就是最后一个编号
//                for (int x = 0; x < lines.size(); x++) {
//                    Integer lineCode = lines.get(x);
//                    if (lineCode == removeLineCode) {
//                        lines.remove(x);
//                        break;
//                    }
//                }
//                //判断是否触发过关
//                if (lines.size() >= 3) {
//                    board = new int[5][5];
//                    level++;
//                }
//            }
//            map.put(level, map.getOrDefault(level, 0) + 1);
//        }
//        for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
//            System.out.println("关卡：" + entry.getKey() + ", 人数：" + entry.getValue());
//        }
//    }

    /**
     * 抽取一次
     * @param activityId 活动ID
     * @param appointPosition 指定落盘位置  null：随机落盘
     * @return SpringDrawOnceDrawResult
     */
    private synchronized SpringDrawOnceDrawResult drawOnce(int activityId, int[] appointPosition) {
        SpringDrawOnceDrawResult result = new SpringDrawOnceDrawResult();
        //获取活动配置
        SpringDrawConfig config = SpringDrawMgr.getActivityConfig(activityId);
        //获取玩家数据
        SpringDrawUserData userData = this.getUserDataAndCreate(activityId, config);
        //获取关卡配置
        SpringDrawDigRewardConfig levelConfig = config.getDigRewardConfig(userData.getLevel());

        //消耗道具
        Property cost = new Property(config.getSPRING_DRAW_ITEM_ID(), levelConfig.getCost());
        boolean costFlag = player.getModule(CurrencyModule.class).removeCurrency(cost, eLogMoneyType.SpringDraw, eLogMoneyType.SpringDrawDrawingCost);
        if (!costFlag) {
            result.setRet(false);
            return result;
        }

        //抽取次数+1
        userData.setDrawNum(userData.getDrawNum() + 1);
        //获取棋盘原本就有的连线
        List<Integer> oldLines = this.checkLines(userData.getBoard());
        //判断是随机落盘，还是指定落盘
        int[] position;
        if (appointPosition == null) {
            //棋盘随机落棋
            position = NLineHelper.changeRandomZerosToOne(userData.getBoard());
        } else {
            //指定落盘
            NLineHelper.changeAppointToOne(userData.getBoard(), appointPosition[0], appointPosition[1]);
            position = appointPosition;
        }
        //获取新棋盘连线
        List<Integer> newLines = this.checkLines(userData.getBoard());
        int lineNum = newLines.size();
        //找出新连成功的线编号,newLines为新的连线
        newLines.removeAll(oldLines);

        //积分奖励
        long addScore = config.drawOnceAddScore(levelConfig.getCost());
        //增加积分道具
        Property scoreReward = new Property(config.getEXCHANGE_SCORE_ITEM_ID(), addScore);
        player.getModule(CurrencyModule.class).addCurrency(scoreReward, eLogMoneyType.SpringDraw, eLogMoneyType.SpringDrawDrawingReward);
        //增加积分
        this.addScore(userData, addScore);

        //连线奖励
        Property lineReward = new Property();
        for (int lineCode : newLines) {
            Property property = levelConfig.getLineReward(lineCode);
            lineReward.addProperty(property);
        }
        player.getModule(CurrencyModule.class).addCurrency(lineReward, eLogMoneyType.SpringDraw, eLogMoneyType.SpringDrawLineReward);
        //增加连续奖励配置的积分
        for (Map.Entry<Integer, BigInteger> entry : lineReward.getGoods().entrySet()) {
            if (entry.getKey() == config.getEXCHANGE_SCORE_ITEM_ID()) {
                this.addScore(userData, entry.getValue().longValue());
            }
        }

        //判断是否能过关
        Property passReward = new Property();
        if (lineNum >= config.getSPRING_DRAW_LINE() && userData.getPassFlag() != SpringDrawPassTypeEnum.SPRING_DRAW_PASS_YES.getType()) {
            //设置成已过关
            userData.setPassFlag(SpringDrawPassTypeEnum.SPRING_DRAW_PASS_YES.getType());
            //过关奖励
            passReward = this.getPassReward(userData, levelConfig);
            player.getModule(CurrencyModule.class).addCurrency(passReward, eLogMoneyType.SpringDraw, eLogMoneyType.SpringDrawPassReward);
            result.setTriggerPassFlag(true);
        }

        //返回
        result.setRet(true);
        result.setPosition(position);
        result.setScoreReward(scoreReward);
        result.setLineReward(lineReward);
        result.setPassReward(passReward);
        return result;
    }

    /**
     * 增加积分
     * @param userData
     * @param addScore
     */
    private synchronized void addScore(SpringDrawUserData userData, long addScore) {
        //判断是否在活动进行期
        ActivityInfo activityInfo = NormalActivityMgr.getActivityInfo(userData.getActivityId());
        if (ActivityHelper.activityInTime(activityInfo)) {
            try {
                //增加积分
                userData.addScore(addScore);
                //排行变动
                player.notifyListener(eGamePlayerEventType.SpringDrawScoreRank.getValue(), userData.getScore());
            } catch (Exception ex) {
                log.error("花袭春意积分排行变动报错，{}", ex);
            }
        }
    }

    /**
     * 获取过关奖励
     * @param userData
     * @param levelConfig
     * @return
     */
    private Property getPassReward(SpringDrawUserData userData, SpringDrawDigRewardConfig levelConfig) {
        Property reward = new Property();
        //自选奖励
        String selectedReward = userData.getSelfSelectRewardMap().get(levelConfig.getLevel());
        if (!StringUtils.isNullOrEmpty(selectedReward)) {
            reward.addProperty(PropertyHelper.parseStringToProperty(selectedReward));
        }
        //固定奖励
        if (!levelConfig.getPassFixedReward().isNothing()) {
            reward.addProperty(levelConfig.getPassFixedReward());
        }
        return reward;
    }

    /**
     * 进入下一关
     * @param reqMsg
     * @return
     * @throws BusinessException
     */
    public synchronized SpringDrawProto.SpringDrawNextLevelRespMsg.Builder enterNextLevel(SpringDrawProto.SpringDrawNextLevelReqMsg reqMsg) throws BusinessException {
        SpringDrawProto.SpringDrawNextLevelRespMsg.Builder respMsg = SpringDrawProto.SpringDrawNextLevelRespMsg.newBuilder();
        //通用检测
        this.checkCommon(reqMsg.getActivityId());
        //获取玩家数据
        SpringDrawUserData userData = this.getUserData(reqMsg.getActivityId());
        if (userData == null) {
            throw BusinessException.newException(GameErrorCode.E_SPRING_DRAW_USER_DATA_NOT_EXIT);
        }
        //判断是否可以下一关
        if (userData.getPassFlag() != SpringDrawPassTypeEnum.SPRING_DRAW_PASS_YES.getType()) {
            throw BusinessException.newException(GameErrorCode.E_SPRING_DRAW_CAN_NOT_NEXT_LEVEL);
        }
        //进入下一关
        this.nextLevel(userData);
        //构造PB
        respMsg.setRet(0);
        SpringDrawProto.SpringDrawUserDataTemp.Builder nextLevelUserDataBuild = SpringDrawPb.buildSpringDrawUserDataTemp(userData.getActivityId(), userData.getUserId(), userData);
        respMsg.setNextLevelUserData(nextLevelUserDataBuild);
        return respMsg;
    }

    /**
     * 选择奖励的函数。
     * @param reqMsg 包含抽奖活动ID和用户选择的奖励信息的请求消息。
     * @return 构建好的包含抽奖结果和用户数据的响应消息。
     * @throws BusinessException 如果出现业务逻辑错误，比如用户数据不存在、选择的奖励不合法等。
     */
    public synchronized SpringDrawProto.SpringDrawSelectRewardRespMsg.Builder selectReward(SpringDrawProto.SpringDrawSelectRewardReqMsg reqMsg) throws BusinessException {
        SpringDrawProto.SpringDrawSelectRewardRespMsg.Builder respMsg = SpringDrawProto.SpringDrawSelectRewardRespMsg.newBuilder();
        //通用检测
        this.checkCommon(reqMsg.getActivityId());
        //获取玩家数据
        SpringDrawUserData userData = this.getUserData(reqMsg.getActivityId());
        if (userData == null) {
            throw BusinessException.newException(GameErrorCode.E_SPRING_DRAW_USER_DATA_NOT_EXIT);
        }
        //获取活动配置
        SpringDrawConfig config = SpringDrawMgr.getActivityConfig(reqMsg.getActivityId());
        //获取关卡配置
        SpringDrawDigRewardConfig levelConfig = config.getDigRewardConfig(reqMsg.getLevel());
        if (levelConfig == null) {
            throw BusinessException.newException(GameErrorCode.E_SPRING_DRAW_LEVEL_CONFIG_NOT_FOUND);
        }
        //判断选择的关卡是否已经过关
        if (userData.getLevel() > reqMsg.getLevel() || (userData.getLevel() == reqMsg.getLevel() && userData.getPassFlag() == SpringDrawPassTypeEnum.SPRING_DRAW_PASS_YES.getType())) {
            throw BusinessException.newException(GameErrorCode.E_SPRING_DRAW_SELECT_REWARD_ERROR_LEVEL_PASSED);
        }
        //判断选择的奖励是否正确
        if (StringUtils.isNullOrEmpty(reqMsg.getReward())) {
            throw BusinessException.newException(GameErrorCode.E_SPRING_DRAW_SELECT_REWARD_EMPTY);
        }
        //判断选择的奖励类型数量是否正确
        String[] selectedRewardList = reqMsg.getReward().split(";");
        if (selectedRewardList.length != levelConfig.getPassSelfSelectReward().size()) {
            throw BusinessException.newException(GameErrorCode.E_SPRING_DRAW_SELECT_REWARD_ERROR);
        }
        //判断选择的奖励是否在选择池子中
        for (int i = 0; i < selectedRewardList.length; i++) {
            //奖励池子
            Property selectRewardPool = levelConfig.getPassSelfSelectReward().get(i);
            //自选的奖励
            String selectedReward = selectedRewardList[i];
            Property selectedRewardProperty = PropertyHelper.parseStringToProperty(selectedReward);
            //判断选择的奖励是否在选择池子中
            for (Map.Entry<Integer, BigInteger> entry : selectedRewardProperty.getGoods().entrySet()) {
                int selectedGoodsId = entry.getKey();
                BigInteger selectedGoodsNum = entry.getValue();
                if (selectedGoodsNum.compareTo(selectRewardPool.getCountByGoodsId(selectedGoodsId)) > 0) {
                    throw BusinessException.newException(GameErrorCode.E_SPRING_DRAW_SELECT_REWARD_ERROR);
                }
            }
        }
        //选择奖励
        userData.putSelfSelectRewardMap(reqMsg.getLevel(), reqMsg.getReward());
        //返回PB
        SpringDrawProto.SpringDrawUserDataTemp.Builder userDataTemp = SpringDrawPb.buildSpringDrawUserDataTemp(userData.getActivityId(), userData.getUserId(), userData);
        respMsg.setRet(0);
        respMsg.setUserData(userDataTemp);
        return respMsg;
    }
}
